package hos.java.util;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import hos.java.compat.CalendarConvert;
import hos.java.func.FunctionReturn;

/**
 * <p>Title: MapUtils </p>
 * <p>Description:  </p>
 * <p>Company: www.mapuni.com </p>
 *
 * @author : 蔡俊峰
 * @version : 1.0
 * @date : 2022/7/22 21:36
 */
public class MapUtils {

    /**
     * 将map转换为List
     *
     * @return List
     */
    public static <K, V> List<K> toListKey(Map<K, V> map) {
        if (map == null || map.isEmpty()) {
            return new LinkedList<>();
        }
        final Set<K> keySet = map.keySet();
        return new LinkedList<>(keySet);
    }

    /**
     * 将map转换为List
     *
     * @return List
     */

    public static <K, V> List<V> toListValue(Map<K, V> map) {
        if (map == null || map.isEmpty()) {
            return new ArrayList<V>();
        }
        final List<V> list = new ArrayList<>();
        final Set<K> keySet = map.keySet();
        for (K key : keySet) {
            V item = map.get(key);
            if (item == null) {
                continue;
            }
            list.add(item);
        }
        return list;
    }

    public static <K, V> V getIfNull(Map<K, V> target, K key, V defaultValue) {
        if (target == null || target.size() == 0 || !target.containsKey(key)) {
            return defaultValue;
        }
        V v = target.get(key);
        if (v == null) {
            return defaultValue;
        } else if (("null".equals(v) || "NULL".equals(v) || "Null".equals(v))) {
            return defaultValue;
        } else {
            return v;
        }
    }


    public static <K, V> V toNull(Map<K, V> target, K key) {
        return getIfNull(target, key, null);
    }

    public static <K, V> String toNullString(Map<K, V> target, K key) {
        V v = toNull(target, key);
        if (v == null) {
            return null;
        }
        return AnyUtils.empty(v);
    }

    public static <K, V> String empty(Map<K, V> target, K key, String start, String end, String defaultValue) {
        String value = toNullString(target, key);
        if (value == null) {
            return start + defaultValue + end;
        }
        return start + value + end;
    }

    public static <K, V> String empty(Map<K, V> target, K key, String start, String end, FunctionReturn<String> defaultValue) {
        String value = toNullString(target, key);
        if (value == null) {
            if (defaultValue == null) {
                return start + end;
            }
            return start + defaultValue.invoke() + end;
        }
        return start + value + end;
    }

    public static <K, V> String empty(Map<K, V> target, K key, String defaultValue) {
        return empty(target, key, "", "", defaultValue);
    }

    public static <K, V> String empty(Map<K, V> target, K key, FunctionReturn<String> supplier) {
        return empty(target, key, "", "", supplier);
    }

    public static <K, V> String empty(Map<K, V> target, K key) {
        return empty(target, key, "");
    }

    public static <K, V> String divide(Map<K, V> target, K key) {
        return empty(target, key, "-");
    }

    public static <K, V> String toEnd(Map<K, V> target, K key, String end, String value) {
        return empty(target, key, "", end, value);
    }

    public static <K, V> String toEnd(Map<K, V> target, K key, String end) {
        return toEnd(target, key, end, "");
    }

    public static <K, V> String toStart(Map<K, V> target, K key, String start) {
        return empty(target, key, start, "", "");
    }

    public static <K, V> String rate(Map<K, V> target, K key) {
        return rate(target, key, "-");
    }

    public static <K, V> String rate(Map<K, V> target, K key, String defaultNull) {
        return empty(target, key, "", "%", defaultNull);
    }

    public static <K, V> String like(Map<K, V> target, K key) {
        String like = toNullString(target, key);
        if (like == null || like.isEmpty()) {
            return "%%";
        }
        return "%" + like + "%";
    }

    //<editor-fold desc="Number">
    public static <K, V> Integer asInteger(Map<K, V> target, K key, Integer defaultValue) {
        return AnyUtils.asInteger(toNull(target, key), defaultValue);
    }

    public static <K, V> int asInteger(Map<K, V> target, K key) {
        return AnyUtils.asInteger(toNull(target, key));
    }

    public static <K, V> Integer toNullInteger(Map<K, V> target, K key) {
        return AnyUtils.toNullInteger(toNull(target, key));
    }

    public static <K, V> String toNullIntegerString(Map<K, V> target, K key) {
        return AnyUtils.toNullIntegerString(toNull(target, key));
    }

    public static <K, V> String asIntegerString(Map<K, V> target, K key, Integer defaultValue) {
        return AnyUtils.asIntegerString(toNull(target, key), defaultValue);
    }

    public static <K, V> String asIntegerString(Map<K, V> target, K key) {
        return AnyUtils.asIntegerString(toNull(target, key));
    }

    public static <K, V> Long asLong(Map<K, V> target, K key, Long defaultValue) {
        return AnyUtils.asLong(toNull(target, key), defaultValue);
    }

    public static <K, V> long asLong(Map<K, V> target, K key) {
        return AnyUtils.asLong(toNull(target, key));
    }

    public static <K, V> Long toNullLong(Map<K, V> target, K key) {
        return AnyUtils.toNullLong(toNull(target, key));
    }

    public static <K, V> String toNullLongString(Map<K, V> target, K key) {
        return AnyUtils.toNullLongString(toNull(target, key));
    }

    public static <K, V> String asLongString(Map<K, V> target, K key, Long defaultValue) {
        return AnyUtils.asLongString(toNull(target, key), defaultValue);
    }

    public static <K, V> String asLongString(Map<K, V> target, K key) {
        return AnyUtils.asLongString(toNull(target, key));
    }

    public static <K, V> Boolean asBoolean(Map<K, V> target, K key, Boolean defaultValue) {
        return AnyUtils.asBoolean(toNull(target, key), defaultValue);
    }

    public static <K, V> boolean asBoolean(Map<K, V> target, K key) {
        return AnyUtils.asBoolean(toNull(target, key));
    }

    public static <K, V> Boolean toNullBoolean(Map<K, V> target, K key) {
        return AnyUtils.toNullBoolean(toNull(target, key));
    }

    public static <K, V> String toNullBooleanString(Map<K, V> target, K key) {
        return AnyUtils.toNullBooleanString(toNull(target, key));
    }

    public static <K, V> String asBooleanString(Map<K, V> target, K key, Boolean defaultValue) {
        return AnyUtils.asBooleanString(toNull(target, key), defaultValue);
    }

    public static <K, V> String asBooleanString(Map<K, V> target, K key) {
        return AnyUtils.asBooleanString(toNull(target, key));
    }

    public static <K, V> Double asDouble(Map<K, V> target, K key, Double defaultValue) {
        return AnyUtils.asDouble(toNull(target, key), defaultValue);
    }

    public static <K, V> double asDouble(Map<K, V> target, K key) {
        return AnyUtils.asDouble(toNull(target, key));
    }

    public static <K, V> Double toNullDouble(Map<K, V> target, K key) {
        return AnyUtils.toNullDouble(toNull(target, key));
    }

    public static <K, V> String toNullDoubleString(Map<K, V> target, K key) {
        return AnyUtils.toNullDoubleString(toNull(target, key));
    }

    public static <K, V> String asDoubleString(Map<K, V> target, K key, Double defaultValue) {
        return AnyUtils.asDoubleString(toNull(target, key), defaultValue);
    }

    public static <K, V> String asDoubleString(Map<K, V> target, K key) {
        return AnyUtils.asDoubleString(toNull(target, key));
    }
    //</editor-fold>

    public static <K, V> String timeNull(Map<K, V> target, K key) {
        return time(target, key, null);
    }

    public static <K, V> String time(Map<K, V> target, K key) {
        return time(target, key, "");
    }

    public static <K, V> String time(Map<K, V> target, K key, String defaultNull) {
        Object orNull = toNull(target, key);
        if (orNull == null) {
            return defaultNull;
        }
        return CalendarConvert.toEmpty(empty(target, key));
    }

    public static <K, V> Calendar calendar(Map<K, V> target, K key, Calendar calendar) {
        String time = timeNull(target, key);
        if (time == null) {
            return calendar;
        }
        return CalendarConvert.string2Calendar(time);
    }

    public static <K, V> Calendar calendar(Map<K, V> target, K key) {
        return calendar(target, key, new GregorianCalendar());
    }

    public static <K, V> String addLength(Map<K, V> target, K key, String defaultNull, int allLength) {
        String orString = toNullString(target, key);
        if (orString == null) {
            orString = defaultNull;
        }
        return StringUtils.addLength(orString, allLength);
    }

    public static <K, V> String addLengthCenter(Map<K, V> target, K key, String defaultNull, int allLength) {
        String value = toNullString(target, key);
        if (value == null) {
            value = defaultNull;
        }
        return StringUtils.addLengthCenter(value, allLength);
    }

    public static <K, V> String addLength(Map<K, V> target, K key, int allLength) {
        return addLength(target, key, "", allLength);
    }

    public static <K, V> String addLengthCenter(Map<K, V> target, K key, int allLength) {
        return addLengthCenter(target, key, "", allLength);
    }

    public static <K, V> String urlParam(Map<K, V> map) {
        Set<K> queryKeys = map.keySet();
        StringBuilder builder = new StringBuilder();
        for (K queryKey : queryKeys) {
            if (builder.length() != 0) {
                builder.append("&");
            }
            Object value = map.get(queryKey);
            if (value != null) {
                builder.append(queryKey).append("=").append(value);
            } else {
                builder.append(queryKey).append("=").append("");
            }
        }
        return builder.toString();
    }
}
